#include "pe.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void DumpPEInfo(const TCHAR* filePath);

#define IsPrintable(a) ((a) >= ' ' && (a) < '~')

static void DumpData(BYTE* data, BYTE* end, unsigned int col)
{
	char buff[2] = {'0', '\0'};
	unsigned int i;


	while (data < end)
	{
		// Print data row view
		for (i = 0; i < col; ++i)
		{
			printf("%02X ", *((BYTE*)data));
			++data;

			if (data == end)
			{
				data += (col - i - 1);
				
				for (++i; i < col; ++i)
					printf("   ");
				
				break;
			}
		}

		data -= col;

		// Print ascii row view
		for (i = 0; i < col; ++i)
		{
			if (IsPrintable(*((BYTE*)data)))
				buff[0] = *((BYTE*)data);
			else
				buff[0] = '.';

			printf("%s", buff);
			++data;

			if (data == end)
				break;
		}

		putchar('\n');
	}
}

#define DumpData(a, b) DumpData(a, b, 19)

static void* ReadBinaryFile(const TCHAR* filePath)
{
	FILE* file;
	void* data;
	unsigned int filesize;


	// Open file
#ifndef UNICODE
	fopen_s(&file, filePath, "rb");
#else
	_wfopen_s(&file, filePath, L"rb");
#endif

	// Get file size
	fseek(file, 0, SEEK_END);
	filesize = ftell(file);
	rewind(file);

	// Get the data
	data = malloc(filesize);
	fread(data, filesize, 1, file);

	fclose(file);

	return data;
}

static void DumpDosHeader(IMAGE_DOS_HEADER* hdr)
{
	printf("//////////// DOS HEADER ////////////\n");
	printf("e_magic: 0x%X\n", hdr->e_magic);
	printf("e_cblp: %d\n", hdr->e_cblp);
	printf("e_cp: %d\n", hdr->e_cp);
	printf("e_crlc: %d\n", hdr->e_crlc);
	printf("e_cparhdr: %d\n", hdr->e_cparhdr);
	printf("e_minalloc: %d\n", hdr->e_minalloc);
	printf("e_maxalloc: %d\n", hdr->e_maxalloc);
	printf("e_ss: %d\n", hdr->e_ss);
	printf("e_sp: %d\n", hdr->e_sp);
	printf("e_csum: %d\n", hdr->e_csum);
	printf("e_ip: %d\n", hdr->e_ip);
	printf("e_cs: %d\n", hdr->e_cs);
	printf("e_lfarlc: %d\n", hdr->e_lfarlc);
	printf("e_ovno: %d\n", hdr->e_ovno);
	printf("e_res: {%d, %d, %d, %d}\n", hdr->e_res[0], hdr->e_res[1], hdr->e_res[2], hdr->e_res[3]);
	printf("e_oemid: %d\n", hdr->e_oemid);
	printf("e_oeminfo: %d\n", hdr->e_oeminfo);
	printf("e_res2: {%d, %d, %d, %d, %d, %d, %d, %d, %d, %d}\n", hdr->e_res2[0], hdr->e_res2[1],
		hdr->e_res2[2], hdr->e_res2[3], hdr->e_res2[4], hdr->e_res2[5],  hdr->e_res2[6],
		hdr->e_res2[7], hdr->e_res2[8], hdr->e_res2[9]);
	printf("e_lfanew: %d\n", hdr->e_lfanew);
}

static void DumpFileHeader(IMAGE_FILE_HEADER* hdr)
{
	printf("//////////// FILE HEADER ////////////\n");
	printf("Machine: 0x%X\n", hdr->Machine);
	printf("NumberOfSections: %d\n", hdr->NumberOfSections);
	printf("TimeDateStamp: %u\n", hdr->TimeDateStamp);
	printf("PointerToSymbolTable: %u\n", hdr->PointerToSymbolTable);
	printf("NumberOfSymbols: %u\n", hdr->NumberOfSymbols);
	printf("SizeOfOptionalHeader: %d\n", hdr->SizeOfOptionalHeader);
	printf("Characteristics: 0x%X\n", hdr->Characteristics);
}

static void DumpOptionalHeader(IMAGE_OPTIONAL_HEADER* hdr)
{
	printf("//////////// OPTIONAL HEADER ////////////\n");
	printf("Magic: 0x%X\n", hdr->Magic);
	printf("MajorLinkerVersion: %d\n", hdr->MajorLinkerVersion);
	printf("MinorLinkerVersion: %d\n", hdr->MinorLinkerVersion);
	printf("SizeOfCode: %u\n", hdr->SizeOfCode);
	printf("SizeOfInitializedData: %u\n", hdr->SizeOfInitializedData);
	printf("SizeOfUninitializedData: %u\n", hdr->SizeOfUninitializedData);
	printf("AddressOfEntryPoint: %u\n", hdr->AddressOfEntryPoint);
	printf("BaseOfCode: %u\n", hdr->BaseOfCode);
	printf("BaseOfData: %u\n", hdr->BaseOfData);
	printf("ImageBase: %u\n", hdr->ImageBase);
	printf("SectionAlignment: %u\n", hdr->SectionAlignment);
	printf("FileAlignment: %u\n", hdr->FileAlignment);
	printf("MajorOperatingSystemVersion: %d\n", hdr->MajorOperatingSystemVersion);
	printf("MinorOperatingSystemVersion: %d\n", hdr->MinorOperatingSystemVersion);
	printf("MajorImageVersion: %d\n", hdr->MajorImageVersion);
	printf("MinorImageVersion: %d\n", hdr->MinorImageVersion);
	printf("MajorSubsystemVersion: %d\n", hdr->MajorSubsystemVersion);
	printf("MinorSubsystemVersion: %d\n", hdr->MinorSubsystemVersion);
	printf("Win32VersionValue: %u\n", hdr->Win32VersionValue);
	printf("SizeOfImage: %u\n", hdr->SizeOfImage);
	printf("SizeOfHeaders: %u\n", hdr->SizeOfHeaders);
	printf("CheckSum: %u\n", hdr->CheckSum);
	printf("Subsystem: %d\n", hdr->Subsystem);
	printf("DllCharacteristics: %d\n", hdr->DllCharacteristics);
	printf("SizeOfStackReserve: %u\n", hdr->SizeOfStackReserve);
	printf("SizeOfStackCommit: %u\n", hdr->SizeOfStackCommit);
	printf("SizeOfHeapReserve: %u\n", hdr->SizeOfHeapReserve);
	printf("SizeOfHeapCommit: %u\n", hdr->SizeOfHeapCommit);
	printf("LoaderFlags: %u\n", hdr->LoaderFlags);
	printf("NumberOfRvaAndSizes: %u\n", hdr->NumberOfRvaAndSizes);
}

static void DumpSectionHeader(IMAGE_SECTION_HEADER* hdr)
{
	char buff[0x100];

	memcpy(buff, hdr->Name, IMAGE_SIZEOF_SHORT_NAME);
	buff[IMAGE_SIZEOF_SHORT_NAME] = '\0';

	printf("//////////// SECTION HEADER ////////////\n");

	printf("Name: %s\n", buff);
	printf("VirtualSize: %u\n", hdr->Misc.VirtualSize);
	printf("VirtualAddress: %u\n", hdr->VirtualAddress);
	printf("SizeOfRawData: %u\n", hdr->SizeOfRawData);
	printf("PointerToRawData: %u\n", hdr->PointerToRawData);
	printf("PointerToRelocations: %u\n", hdr->PointerToRelocations);
	printf("PointerToLinenumbers: %u\n", hdr->PointerToLinenumbers);
	printf("NumberOfRelocations: %d\n", hdr->NumberOfRelocations);
	printf("NumberOfLinenumbers: %d\n", hdr->NumberOfLinenumbers);
	printf("Characteristics: 0x%X\n", hdr->Characteristics);
}


void DumpPEInfo(const TCHAR* filePath)
{
	unsigned int i;

	BYTE* pe = (BYTE*)ReadBinaryFile(filePath);

	IMAGE_DOS_HEADER* dosHdr;
	IMAGE_FILE_HEADER* imgFileHdr;
	IMAGE_OPTIONAL_HEADER* imgOptHdr;
	IMAGE_SECTION_HEADER* imgSectHdr;

	/* FILE* textf; */
	/* BYTE* bp; */

	dosHdr = (IMAGE_DOS_HEADER*)pe;
	imgFileHdr = (IMAGE_FILE_HEADER*)(pe + (dosHdr->e_lfanew + 4));
	imgOptHdr = (IMAGE_OPTIONAL_HEADER*)((BYTE*)imgFileHdr + sizeof(IMAGE_FILE_HEADER));

	DumpDosHeader(dosHdr);
	putchar('\n');
	DumpFileHeader(imgFileHdr);
	putchar('\n');
	DumpOptionalHeader(imgOptHdr);
	putchar('\n');

	for (i = 0, imgSectHdr = (IMAGE_SECTION_HEADER*)((BYTE*)imgOptHdr + sizeof(IMAGE_OPTIONAL_HEADER));
		 i < imgFileHdr->NumberOfSections;
		 ++i, ++imgSectHdr)
	{
		DumpSectionHeader(imgSectHdr);
		
#if 0
		printf("\n//////////// SECTION RAW DATA ////////////\n");

		if (imgSectHdr->Name[0] == '.' && 
			imgSectHdr->Name[1] == 't' &&
			imgSectHdr->Name[2] == 'e')
		{
			textf = fopen(".\\text.txt", "w");

			for (bp = pe + imgSectHdr->PointerToRawData; bp != (BYTE*)pe + (imgSectHdr->PointerToRawData + imgSectHdr->SizeOfRawData) && *bp != 0xC3; ++bp)
			{
				fprintf(textf, (*(bp + 1) != 0xC3 && (bp + 1) != (BYTE*)pe + (imgSectHdr->PointerToRawData + imgSectHdr->SizeOfRawData)) ? "0x%02X, " : "0x%02X", *bp);
			}

			fclose(textf);
		}
		
		DumpData((BYTE*)pe + imgSectHdr->PointerToRawData, (BYTE*)pe + (imgSectHdr->PointerToRawData + imgSectHdr->SizeOfRawData));

		putchar('\n');
#endif
	}

	free(pe);
}